
(function (w) {
    function MapDXF(id, width, height) {
        this.docBind = document.getElementById(id)
        this.width = width
        this.height = height
        this.ctx = undefined // 画笔
        this.docCancas = undefined // 画布
        this.data = undefined // 数据
        this.layer = undefined
        this.coverages = ['mapCanvas'] // 所有图层ID

        // 初始化地图计算数据
        this.scale = 1 // 总图比例
        this.drawScale = 1 // 初始化画地图比列
        this.offsetX = 0 // 画图偏移量
        this.offsetY = 0 // 画图偏移量
        this.margin = 0 // 外边距
        this.drawFuns = [] // 画图方法
        this.cancasWidth = width // 当前画布宽
        this.cancasHeight = height // 当前画布高

        this.mouseX = 0
        this.mouseY = 0
        this.leftX = 0
        this.topY = 0
        this.dragging = false
        this.zoomStepLength = 0.2// 缩放步长
        this.textScale = 1 // 文字对比cad缩放比例
        this.lineWidth = 0.66 // 线宽
        this.lineColor = '#fff'

        this.zoomWidth = 1
        this.translateX = 0
        this.translateY = 0

        this.zoomTranslateX = 0
        this.zoomTranslateY = 0
        // 创建画布
        this._addCanvas()
        // 绑定事件
        this._bind()
    }

    // 给原型扩展方法
    MapDXF.prototype = {

        constructor: MapDXF,
        _addCanvas() {
            // 图层层画地图外面层
            const layer = document.createElement('div')
            layer.id = 'layer'
            layer.style.position = 'absolute'
            layer.classList.add('layer')

            // 画布图层
            const canvas = document.createElement('canvas')
            canvas.id = 'mapCanvas'
            canvas.classList.add('mapCanvas')
            canvas.width = this.width * this.scale
            canvas.height = this.height * this.scale
            layer.appendChild(canvas)

            this.docBind.innerHTML = ''
            this.docBind.appendChild(layer)

            // 初始化画布元素
            this.layer = document.getElementById('layer')
            this.docCancas = document.getElementById('mapCanvas')
            this.ctx = this.docCancas.getContext('2d')
        },

        // ==============缩放及移动逻辑start====================
        // 移动图层
        // 绑定事件
        _bind() {
            const _this = this
            // eslint-disable-next-line space-before-function-paren
            this.docBind.onmousedown = function (event) {
                _this.dragging = true
                _this.mouseX = event.clientX
                _this.mouseY = event.clientY
            }
            // eslint-disable-next-line space-before-function-paren
            this.docBind.onmousemove = function (evt) { // 移动
                if (_this.dragging) {
                    const moveX = evt.clientX - _this.mouseX
                    const moveY = evt.clientY - _this.mouseY
                    _this.mouseX = evt.clientX
                    _this.mouseY = evt.clientY
                    _this.translateX += (moveX / _this.zoomWidth)
                    _this.translateY += (moveY / _this.zoomWidth)

                    _this.draw()
                }
            }
            // eslint-disable-next-line space-before-function-paren
            this.docBind.onmouseup = function () {
                _this.dragging = false
            }
            // eslint-disable-next-line space-before-function-paren
            this.docBind.onmousewheel = this.docBind.onwheel = function (event) { // 滚轮放大缩小
                // 放大缩小思路：计算放大缩小倍数、画线同样放大收缩
                // event.wheelDelta > 0//放大 缩小
                let zoom
                if (event.wheelDelta > 0) {
                    _this.zoomWidth += _this.zoomStepLength
                    zoom = -_this.zoomStepLength
                } else {
                    _this.zoomWidth -= _this.zoomStepLength
                    zoom = _this.zoomStepLength
                    if (_this.zoomWidth <= 0.2) {
                        alert('地图已经最小,无法再缩小')
                        _this.zoomWidth += _this.zoomStepLength
                        return
                    }
                }

                // 移动画布使画布在鼠标处缩放
                const box = _this.docCancas.getBoundingClientRect()
                const x = event.clientX - box.left
                const y = -(_this.docCancas.height - (event.clientY - box.top))

                _this.zoomTranslateX = _this.zoomTranslateX + x * zoom
                _this.zoomTranslateY = _this.zoomTranslateY + y * zoom

                _this.draw()
            }
        },
        // ==============缩放及移动逻辑end====================
        // ==============画地图逻辑start====================
        init(data) {
            this.data = data
            // 初始所有图像都放在地图显示，此时只能放大不能缩小
            // 1.计算最大和最小两点
            // 下基准点取最小坐标，为0，0点
            const minPoint = { x: this.data.MinX, y: this.data.MinY }

            let maxPoint

            const maxY = this.data.MaxX * this.height / this.width
            if (maxY > this.data.MaxY) {
                maxPoint = { x: this.data.MaxX, y: maxY }
            } else {
                maxPoint = { x: this.data.MaxY * this.width / this.height, y: this.data.MaxY }
            }

            // 2.计算比例 （最大点X-最小点X+20预留边距离）
            this.drawScale = this.width / (maxPoint.x - minPoint.x)

            // 3.计算偏移（原点-最小点+边距）
            this.offsetX = 0 - minPoint.x
            this.offsetY = 0 - minPoint.y

            // 添加画图方法
            this.drawFuns = []
            this.drawFuns.Text = this.drawText
            this.drawFuns.Line = this.drawLine
            this.drawFuns.LightWeightPolyline = this.drawLightWeightPolyline
            this.drawFuns.Circle = this.drawCircle

            // 画图
            this.draw()
        },
        // 绘制
        draw(x, y) {
            // 画布原点位置为左上角，将其转换笛卡尔坐标轴
            this.ctx.clearRect(-this.docCancas.width * 500, -this.docCancas.height * 500, this.docCancas.width * 1000, this.docCancas.height * 1000)

            this.ctx.lineWidth = this.lineWidth
            this.ctx.strokeStyle = this.lineColor
            const map = this.data.Map
            map.forEach(e => {
                if (this.drawFuns[e.Type]) {
                    this.drawFuns[e.Type].call(this, e)
                } else {
                    console.log('类型未找到：' + e.Type)
                }
            })
        },
        // 将CAD地图坐标转换为cancas坐标
        convertX(coord) {
            // 1.偏移
            coord = coord + this.offsetX
            let x = this.convert(coord)

            x = x + this.translateX * this.zoomWidth + this.zoomTranslateX

            return x
        },
        convertY(coord) {
            // 1.偏移
            coord = coord + this.offsetY

            const y = this.convert(coord)
            // 计算Y轴偏移及反转
            let yy = this.docCancas.height - y

            yy = yy + this.translateY * this.zoomWidth + this.zoomTranslateY

            return yy
        },
        convert(coord) {
            // 2.初始缩放
            coord = coord * this.drawScale
            // 3.地图缩放
            coord = coord * this.zoomWidth

            return coord
        },
        drawLine(data) {
            const points = data.Points

            this.ctx.beginPath()

            this.ctx.moveTo(this.convertX(points[0].X), this.convertY(points[0].Y))
            this.ctx.lineTo(this.convertX(points[1].X), this.convertY(points[1].Y))
            this.ctx.stroke()
        },
        drawLightWeightPolyline(data) {
            const points = data.Points.slice(0, data.Points.length)

            this.ctx.beginPath()

            this.ctx.moveTo(this.convertX(points[0].X), this.convertY(points[0].Y))
            points.shift()
            points.forEach(e => {
                this.ctx.lineTo(this.convertX(e.X), this.convertY(e.Y))
            })
            if (data.IsClose) {
                this.ctx.closePath()
            }
            this.ctx.stroke()
        },
        drawCircle(data) {
            if (data.Radius > 0) {
                const point = data.Point
                this.ctx.beginPath()
                this.ctx.arc(this.convertX(point.X), this.convertY(point.Y), this.convert(data.Radius), 0, 2 * Math.PI)
                this.ctx.stroke()
            }
        },
        circle() {
            this.ctx.beginPath()
            this.ctx.arc(this.convertX(250), this.convertY(250), 4, 0, 2 * Math.PI)
            this.ctx.arc(this.convertX(0), this.convertY(0), 4, 0, 2 * Math.PI)
            this.ctx.stroke()
        },
        drawText(data) {
            const point = data.Point
            const x = this.convertX(point.X)
            const y = this.convertY(point.Y)

            this.ctx.beginPath()
            this.ctx.font = this.convert(data.Height) * this.textScale + 'px 微软雅黑'
            this.ctx.fillStyle = this.lineColor
            this.ctx.fillText(data.Value, x, y)
            this.ctx.stroke()
        },
        // ==============画地图逻辑end====================
        _getRad(degree) {
            return degree / 180 * Math.PI
        }
    }

    //向外部暴露对象
    w.getMapDXF = function (id, width, height) {
        return new MapDXF(id, width, height)
    }

}(window));